namespace PayPal
{
    using System;
    using System.Collections.Generic;
    using System.Web.WebPages.Scope;

    public static class Profile
    {
        private static readonly IDictionary<string, PayPalEnvironment> _environments = new Dictionary<string, PayPalEnvironment>(StringComparer.OrdinalIgnoreCase) { { "production", PayPalEnvironment.Production }, { "sandbox", PayPalEnvironment.Sandbox } };
        private const string NullMessage = "Argument cannot be null or empty";

        private static readonly object _apiUsernameKey = new object();
        private static readonly object _apiPasswordKey = new object();
        private static readonly object _apiSignatureKey = new object();
        private static readonly object _environmentKey = new object();
        private static readonly object _appIdKey = new object();
        private static readonly object _initializedKey = new object();

        private static readonly object _languageKey = new object();
        private static readonly object _ipnUrlKey = new object();
        private static readonly object _returnUrlKey = new object();
        private static readonly object _cancelUrlKey = new object();
        private static readonly object _currencyCodeKey = new object();

        public static string ApiUsername
        {
            get
            {
                return (string)(ScopeStorage.CurrentScope[_apiUsernameKey] ?? "");
            }

            private set
            {
                ScopeStorage.CurrentScope[_apiUsernameKey] = value;
            }
        }
       
        public static string ApiPassword
        {
            get
            {
                return (string)(ScopeStorage.CurrentScope[_apiPasswordKey] ?? "");
            }

            private set
            {
                ScopeStorage.CurrentScope[_apiPasswordKey] = value;
            }
        }
        
        public static string ApiSignature
        {
            get
            {
                return (string)(ScopeStorage.CurrentScope[_apiSignatureKey] ?? "");
            }

            private set
            {
                ScopeStorage.CurrentScope[_apiSignatureKey] = value;
            }
        }
        
        public static string Environment
        {
            get
            {
                return (string)(ScopeStorage.CurrentScope[_environmentKey] ?? "");
            }

            private set
            {
                ScopeStorage.CurrentScope[_environmentKey] = value;
            }
        }
        
        public static string ApplicationId
        {
            get
            {
                return (string)(ScopeStorage.CurrentScope[_appIdKey] ?? "");
            }

            private set
            {
                ScopeStorage.CurrentScope[_appIdKey] = value;
            }
        }

        public static string Language
        {
            get
            {
                return (string)(ScopeStorage.CurrentScope[_languageKey] ?? "");
            }

            set
            {
                ScopeStorage.CurrentScope[_languageKey] = value;
            }
        }

        public static string IpnUrl
        {
            get
            {
                return (string)(ScopeStorage.CurrentScope[_ipnUrlKey] ?? "");
            }

            set
            {
                ScopeStorage.CurrentScope[_ipnUrlKey] = value;
            }
        }

        public static string ReturnUrl
        {
            get
            {
                return (string)(ScopeStorage.CurrentScope[_returnUrlKey] ?? "");
            }

            set
            {
                ScopeStorage.CurrentScope[_returnUrlKey] = value;
            }
        }

        public static string CancelUrl
        {
            get
            {
                return (string)(ScopeStorage.CurrentScope[_cancelUrlKey] ?? "");
            }

            set
            {
                ScopeStorage.CurrentScope[_cancelUrlKey] = value;
            }
        }

        public static string CurrencyCode
        {
            get
            {
                return (string)(ScopeStorage.CurrentScope[_currencyCodeKey] ?? "");
            }

            set
            {
                ScopeStorage.CurrentScope[_currencyCodeKey] = value;
            }
        }

        internal static PayPalEnvironment PayPalEnvironment
        {
            get
            {
                EnsureInitalized();
                return _environments[Profile.Environment];
            }
        }

        internal static com.paypal.sdk.profiles.IAPIProfile BMProfile
        {
            get
            {
                EnsureInitalized();

                var profile = com.paypal.sdk.profiles.ProfileFactory.createSignatureAPIProfile();
                profile.APIUsername = Profile.ApiUsername;
                profile.APIPassword = Profile.ApiPassword;
                profile.Subject = "";
                profile.APISignature = Profile.ApiSignature;
                profile.Environment = Profile.Environment;

                return profile;
            }
        }

        internal static PayPal.Platform.SDK.BaseAPIProfile FNProfile
        {
            get
            {
                EnsureInitalized();

                var profile = new PayPal.Platform.SDK.BaseAPIProfile();
                profile.APIUsername = Profile.ApiUsername;
                profile.APIPassword = Profile.ApiPassword;
                profile.APISignature = Profile.ApiSignature;
                profile.APIProfileType = PayPal.Platform.SDK.ProfileType.ThreeToken;
                profile.RequestDataformat = PayPal.Platform.SDK.BaseConstants.RequestDataformat;
                profile.ResponseDataformat = PayPal.Platform.SDK.BaseConstants.ResponseDataformat;
                profile.Environment = Profile.PayPalEnvironment == PayPalEnvironment.Sandbox ? UrlConstants.SandboxEnvironmentUrl : UrlConstants.ProductionEnvironmentUrl;
                profile.ApplicationID = Profile.ApplicationId;

                return profile;
            }
        }

        private static bool Initialized
        {
            get
            {
                return (bool)(ScopeStorage.CurrentScope[_initializedKey] ?? false);
            }

            set
            {
                ScopeStorage.CurrentScope[_initializedKey] = value;
            }
        }

        /// <summary>
        /// Initializes the PayPal Helper, both for using the Button Manager API and the Adaptive Payments API
        /// </summary>
        /// <param name="apiUsername">Your API username</param>
        /// <param name="apiPassword">Your API password</param>
        /// <param name="apiSignature">Your API signature</param>
        /// <param name="environment">The environment in which you want to execute the API operation: 'sandbox' or 'production'</param>
        /// <param name="applicationId">The Application Id. A default testing Application Id is provided ONLY for testing purposes</param>
        public static void Initialize(
                                string apiUsername,
                                string apiPassword,
                                string apiSignature,
                                string environment,
                                string applicationId = "APP-80W284485P519543T")
        {
            if (String.IsNullOrEmpty(apiUsername))
            {
                throw new ArgumentException(NullMessage, "apiUserName");
            }

            if (String.IsNullOrEmpty(environment))
            {
                throw new ArgumentException(NullMessage, "environment");
            }

            if (!_environments.ContainsKey(environment))
            {
                throw new ArgumentException("Environment is not recognized, please use 'sandbox' or 'production'");
            }

            Profile.ApiUsername = apiUsername;
            Profile.ApiPassword = apiPassword;
            Profile.ApiSignature = apiSignature;
            Profile.Environment = environment.ToLowerInvariant();
            Profile.ApplicationId = applicationId;

            Profile.Initialized = true;
        }

        private static void EnsureInitalized()
        {
            if (!Initialized)
            {
                throw new InvalidOperationException("The PayPal Helper has not been initialized.");
            }
        }
    }
}